using System;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;

namespace Com.Core.Validation;

public class ChineseIDCardAttribute: ValidationAttribute
{
    private static readonly string[] ValidProvinceCodes = 
    {
        "11", "12", "13", "14", "15", "21", "22", "23", 
        "31", "32", "33", "34", "35", "36", "37", "41", 
        "42", "43", "44", "45", "46", "50", "51", "52", 
        "53", "54", "61", "62", "63", "64", "65", "71", 
        "81", "82", "91"
    };
    
    private static readonly int[] WeightFactors = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
    private static readonly char[] CheckCodes = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };

    protected override ValidationResult? IsValid(object? value, ValidationContext context)
    {
        // 允许空值（由[Required]处理必填逻辑）
        if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
        {
            return ValidationResult.Success;
        }

        string id = value.ToString()!.Trim();
        
        if (id.Length == 18)
        {
            if (!CheckIDCard18(id))
            {
                return new ValidationResult(ErrorMessage ?? "无效的身份证号码");
            }
        }
        else if (id.Length == 15)
        {
            if (!CheckIDCard15(id))
            {
                return new ValidationResult(ErrorMessage ?? "无效的身份证号码");
            }
        }
        else
        {
            return new ValidationResult(ErrorMessage ?? "身份证号长度应为15位或18位");
        }

        return ValidationResult.Success;
    }

    /// <summary>
    /// 验证身份证号
    /// </summary>
    /// <param name="id">身份证号</param>
    /// <returns>是否有效</returns>
    public static bool IsValid(string id)
    {
        if (id.Length == 18)
        {
            return CheckIDCard18(id);
        }
        else if (id.Length == 15)
        {
            return CheckIDCard15(id);
        }
        else
        {
            return false;
        }
    }

    /// <summary>
    /// 验证18位身份证号
    /// </summary>
    private static bool CheckIDCard18(string id)
    {
        // 基本格式验证
        if (!Regex.IsMatch(id, @"^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[0-9Xx]$"))
            return false;

        // 省份验证
        string provinceCode = id.Substring(0, 2);
        if (Array.IndexOf(ValidProvinceCodes, provinceCode) == -1)
            return false;

        // 日期验证
        string dateStr = $"{id.Substring(6, 4)}-{id.Substring(10, 2)}-{id.Substring(12, 2)}";
        if (!DateTime.TryParse(dateStr, out DateTime birthDate))
            return false;
        
        // 校验码验证
        int sum = 0;
        for (int i = 0; i < 17; i++)
        {
            if (!int.TryParse(id[i].ToString(), out int digit))
                return false;
                
            sum += digit * WeightFactors[i];
        }

        int remainder = sum % 11;
        char expectedCheckCode = CheckCodes[remainder];
        
        return char.ToUpper(id[17]) == expectedCheckCode;
    }

    /// <summary>
    /// 验证15位身份证号
    /// </summary>
    private static bool CheckIDCard15(string id)
    {
        // 基本格式验证
        if (!Regex.IsMatch(id, @"^[1-9]\d{5}\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}$"))
            return false;

        // 省份验证
        string provinceCode = id.Substring(0, 2);
        if (Array.IndexOf(ValidProvinceCodes, provinceCode) == -1)
            return false;

        // 日期验证（添加19世纪前缀）
        string yearPrefix = "19";
        string dateStr = $"{yearPrefix}{id.Substring(6, 2)}-{id.Substring(8, 2)}-{id.Substring(10, 2)}";
        
        return DateTime.TryParse(dateStr, out _);
    }
}
